﻿using IdentityModel;
using Microsoft.AspNetCore.Authorization;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Controllers;
using Microsoft.AspNetCore.Mvc.Filters;
using Microsoft.Extensions.DependencyInjection;
using Newtonsoft.Json;
using Rabc.Project.Repositories;
using Rbac.Domain;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Dynamic.Core;
using System.Net;
using System.Reflection;
using System.Security.Claims;
using System.Text.Json.Serialization;

namespace Rbac.Project.WebApi.Filters
{
    [AttributeUsage(AttributeTargets.Class | AttributeTargets.Method, AllowMultiple = true, Inherited = true)]
    public class CustomerAuthorizationFilterAttribute : AuthorizeAttribute, IAuthorizationFilter
    {
        public void OnAuthorization(AuthorizationFilterContext context)
        {
            if (context.ActionDescriptor.EndpointMetadata.Any(m => m is IAllowAnonymous))
                return;
            #region 二选一
            /*ControllerActionDescriptor descriptor = context.ActionDescriptor as ControllerActionDescriptor;
            string DisplayName = context.ActionDescriptor.DisplayName;
            string ControllerName = descriptor.ControllerName;
            string ActionName = descriptor.ActionName;

            if (descriptor.MethodInfo.GetCustomAttributes<AllowAnonymousAttribute>().Any())
            {
                return;
            }*/
            #endregion

            string AttributeRouteInfo = "/" + context.ActionDescriptor.AttributeRouteInfo.Template;

            bool isLogin = context.HttpContext.User.Identity.IsAuthenticated;
            if (!isLogin)
            {
                context.Result = new StatusCodeResult((int)HttpStatusCode.Unauthorized);
            }
            else
            {
                if (!context.ActionDescriptor.EndpointMetadata.Any(m => m is IAuthorizationFilter))
                {
                    IServiceProvider serviceProvider = context.HttpContext.RequestServices;
                    var menuRepository = serviceProvider.GetService<IRepository<Menu>>();
                    var roleMenuRepository = serviceProvider.GetService<IRepository<RoleMenu>>();

                    var menuRoleId = roleMenuRepository.Queryable()
                        .Where(m => menuRepository.Queryable().Where(menu => menu.MenuAPI == AttributeRouteInfo)
                        .Select(s => s.MenuId).Contains(m.MenuID)).Select(m=>m.RoleID).ToList();

                    //SELECT RoleID FROM Menus INNER JOIN RoleMenus ON Menus.MenuId = RoleMenus.MenuID WHERE MenuAPI = '/Menu/GetTreeNodes'
                    /*var list = menuRepository.Queryable()
                        .Join(roleMenuRepository.Queryable(), a => a.MenuId, b => b.MenuID, (a, b) =>new { a.MenuAPI,b.RoleID })
                        .Where(m=>m.MenuAPI == AttributeRouteInfo)
                        .Select(m=>m.RoleID)
                        .ToList();*/

                    string UserName = context.HttpContext.User.Identity.Name;
                    IEnumerable<Claim> claims = context.HttpContext.User.Claims;

                    int[] roleid = claims.First(m => m.Type == ClaimTypes.Role).Value.Split(',')
                        .Select(m=>Convert.ToInt32(m)).ToArray();

                    //var adminRoleId = Array.ConvertAll(roleid, m => Convert.ToInt32(m));

                    if(!roleid.Any(m => menuRoleId.Contains(m)))
                    {
                        context.Result = new StatusCodeResult((int)HttpStatusCode.Forbidden);
                    }
                }
            }
        }
    }
}
